const objData = {
  name: "zs",
  age: "14",
  gender: "男",
};

function identity<T extends keyof typeof objData>(type: T) {
  return objData[type];
}

identity("name");
console.log(identity("name"));

const dataObj = {
  name: "ls",
  age: 20,
};

function fun<T>(obj: T, key: keyof T) {
  return obj[key];
}

console.log(fun(dataObj, "name"));

const someArray = [1, "string", false];

for (let entry of someArray) {
  console.log(entry); // 1, "string", false
}

// 手写Pick 从泛型Type中获取指定属性的类型，相当于得到的新类型只包含你所指定的泛型第二个参数的属性的类型。
interface IPerson {
  name: string;
  age: number;
  gender: string;
}

type PickType = Pick<IPerson, "name" | "age">;

const stas: PickType = {
  name: "章三",
  age: 12,
};

function Test<T>(v: T): T {
  return v;
}
Test(1);

type myPick<T, K extends keyof T> = {
  [P in K]: T[P];
};

interface User {
  id: number;
  name: string;
  age: number;
}

type UserSubset = myPick<User, "name" | "age">;

const user: UserSubset = {
  name: "123",
  age: 12,
};

function test(v: UserSubset) {
  return v;
}

test({
  name: "123",
  age: 1231234213,
});

// 手写Partial 其构造一个将 Type 的所有属性设置为可选的类型。此工具将返回一个表示给定类型的所有子集的类型
type myPartial<T> = {
  [P in keyof T]?: T[P];
};

type user1 = {
  name: string;
  age: number;
  gender: string;
};

type user2 = myPartial<user1>;

function user3(key: user2) {
  return key;
}
console.log(user3({ age: 12 }));

// 手写Record 构造一个对象类型，其属性键为 Keys，其属性值为 Type。可用于将一种类型的属性映射到另一种类型。
type MyRecord<K extends keyof any, T> = {
  [P in K]: T;
};

type PageInfo = {
  title: string;
  url: string;
  age: number;
};

const nav: MyRecord<string, PageInfo> = {
  home: { title: "Home", url: "/", age: 1232 },
};
console.log(nav);

// 手写Omit 通过从 Type 中选择所有属性然后删除 Keys（字符串字面或字符串字面的并集）来构造一个类型。与 Pick 相反。
type MyOmit<T, K extends keyof T> = {
  [P in Exclude<keyof T, K>]: T[P];
}
interface Person {
  name: string;
  email: string;
  age: number;
}

type OmitPerson = MyOmit<Person, "age">;

const persons: OmitPerson = {
  name: "dolphin",
  email: "dolphin@meituan.com",
};

// 手写Exclude 从类型 T 中剔除可以赋值给 U 的类型
type myExclude<T, U> = T extends U ? never : T

type PersonKeys = "name" | "email" | "age";
type ExcludePerson = myExclude<PersonKeys, "age">;

const person: ExcludePerson = "name"; // 只能是 "name" 或 "email"

// 手写ReturnType  与 Partial 相反。Required把传入泛型Type的属性都变为必选项。
type myRequired<T> = { [P in keyof T]-?: T[P]; }
interface Props {
  a: number;
  b: string;
}

const obj2: myRequired<Props> = { a: 5, b: '1' };
console.log(obj2)
